package aiyh.utils.sqlUtil.builderSql.impl;


import aiyh.utils.Util;
import aiyh.utils.mapUtil.UtilHashMap;
import aiyh.utils.mapUtil.UtilLinkedHashMap;
import aiyh.utils.sqlUtil.builderSql.BuilderSql;
import aiyh.utils.sqlUtil.sqlResult.impl.PrepSqlResultImpl;
import aiyh.utils.sqlUtil.sqlResult.impl.BatchSqlResultImpl;
import aiyh.utils.sqlUtil.whereUtil.Where;
import aiyh.utils.sqlUtil.whereUtil.impl.WhereImpl;
import weaver.conn.RecordSet;


import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author EBU7-dev1-ayh
 * @date 2021/8/23 0023 14:45
 */


public class BuilderSqlImpl implements BuilderSql {
	private String DB_TYPE;

	{
//		获取当前数据库的类型
		this.DB_TYPE = (new RecordSet()).getDBType();
	}

	/**
	 * 构建插入语句
	 * @param tableName 数据库表名
	 * @param mapConfig 数据库字段和值
	 * @return 自定义SQL实体类
	 */
	@Override
	public PrepSqlResultImpl insertSql(String tableName, Map<String, Object> mapConfig) {
		UtilHashMap<String, Object> map = this.verifyMap(mapConfig);
		List<Object> args = new ArrayList<>();
		StringBuilder sqlBuilder = new StringBuilder("insert into ");
		sqlBuilder.append(tableName);
		StringBuilder fieldBuilder = new StringBuilder();
		StringBuilder valueBuilder = new StringBuilder();
		map.forEach((field, value) -> {
			fieldBuilder.append(field);
			fieldBuilder.append(", ");
			valueBuilder.append(" ?, ");
			args.add(value);
		});
		sqlBuilder.append(" ( ");
		sqlBuilder.append(Util.removeSeparator(fieldBuilder));
		sqlBuilder.append(" ) values ( ");
		sqlBuilder.append(Util.removeSeparator(valueBuilder));
		sqlBuilder.append(" )");
		return new PrepSqlResultImpl(sqlBuilder.toString(), args);
	}

    /**
     * 通过实体类构建插入SQL
     * @param tableName 数据库表名
     * @param t 实体类对象
     * @param <T> 实体类对象泛型
     * @return SQL结果对象
     */
	public <T> PrepSqlResultImpl insertSqlByEntity(String tableName, T t){
		List<Object> args = new ArrayList<>();
		StringBuilder sqlBuilder = new StringBuilder("insert into ");
		sqlBuilder.append(tableName);
		StringBuilder fieldBuilder = new StringBuilder();
		StringBuilder valueBuilder = new StringBuilder();

		BeanInfo beanInfo = null;
		try {
			beanInfo = Introspector.getBeanInfo(t.getClass(), Object.class);
			PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
			for (PropertyDescriptor proper : propertyDescriptors) {
				String name = proper.getName();
				Method readMethod = proper.getReadMethod();
				Object invoke = readMethod.invoke(t);
//				System.out.println(name);
//				System.out.println(invoke);
				if(invoke == null){
					continue;
				}
				fieldBuilder.append(name);
				fieldBuilder.append(", ");
				valueBuilder.append(" ?, ");
				args.add(invoke);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		sqlBuilder.append(" ( ");
		sqlBuilder.append(Util.removeSeparator(fieldBuilder));
		sqlBuilder.append(" ) values ( ");
		sqlBuilder.append(Util.removeSeparator(valueBuilder));
		sqlBuilder.append(" )");
		return new PrepSqlResultImpl(sqlBuilder.toString(), args);
	}

	/**
	 * 构建批量插入SQL
	 * @param tableName 表名
	 * @param mapListConfig 表对应的字段和值映射list
	 * @return 自定义批量SQL实体类
	 */
	@Override
	public BatchSqlResultImpl insertBatchSql(String tableName, List<LinkedHashMap<String, Object>> mapListConfig) {
		List<UtilLinkedHashMap<String, Object>> mapList = this.verifyMapList(mapListConfig);
		StringBuilder sqlBuilder = new StringBuilder("insert into ");
		sqlBuilder.append(tableName);
		StringBuilder fieldBuilder = new StringBuilder();
		StringBuilder valueBuilder = new StringBuilder();
		List<List> args = new ArrayList<>();
		AtomicInteger i = new AtomicInteger();
		mapList.forEach(item -> {
			List<Object> arg = new ArrayList<>();
			item.forEach((field, value) -> {
				if (i.get() == 0) {
					fieldBuilder.append(field);
					fieldBuilder.append(", ");
					valueBuilder.append(" ?, ");
				}
				arg.add(value);
			});
			args.add(arg);
			i.getAndIncrement();
		});
		sqlBuilder.append(" ( ");
		sqlBuilder.append(Util.removeSeparator(fieldBuilder));
		sqlBuilder.append(" ) values ( ");
		sqlBuilder.append(Util.removeSeparator(valueBuilder));
		sqlBuilder.append(" )");
		return new BatchSqlResultImpl(sqlBuilder.toString(), args);
	}

    /**
     * 构建批量插入SQL
     * @param tableName 数据库表名
     * @param list 实体类数组
     * @param <T> 实体类泛型
     * @return SQL对象
     */
	public <T> BatchSqlResultImpl insertBatchSqlByEntity(String tableName, List<T> list) {
		StringBuilder sqlBuilder = new StringBuilder("insert into ");
		sqlBuilder.append(tableName);
		StringBuilder fieldBuilder = new StringBuilder();
		StringBuilder valueBuilder = new StringBuilder();
		List<List> args = new ArrayList<>();
		AtomicInteger i = new AtomicInteger();

		list.forEach(item -> {
			List<Object> arg = new ArrayList<>();
			BeanInfo beanInfo = null;

			try {
				beanInfo = Introspector.getBeanInfo(item.getClass(), Object.class);
				PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
				for (PropertyDescriptor proper : propertyDescriptors) {
					String name = proper.getName();
					Method readMethod = proper.getReadMethod();
					Object invoke = readMethod.invoke(item);
					if(invoke == null){
						continue;
					}
					if (i.get() == 0) {
						fieldBuilder.append(name);
						fieldBuilder.append(", ");
						valueBuilder.append(" ?, ");
					}
					arg.add(invoke);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			args.add(arg);
			i.getAndIncrement();
		});
		sqlBuilder.append(" ( ");
		sqlBuilder.append(Util.removeSeparator(fieldBuilder));
		sqlBuilder.append(" ) values ( ");
		sqlBuilder.append(Util.removeSeparator(valueBuilder));
		sqlBuilder.append(" )");
		return new BatchSqlResultImpl(sqlBuilder.toString(), args);
	}

	/**
	 *  构建更新语句
	 * @param tableName 表名
	 * @param mapConfig 表名所对应键值对
	 * @param where 更新数据的条件
	 * @return 自定义SQL实体类
	 */
	@Override
	public PrepSqlResultImpl updateSql(String tableName, Map<String, Object> mapConfig, Where where) {
		UtilHashMap<String, Object> map = this.verifyMap(mapConfig);
		this.verifyWhere(where);
		StringBuilder sqlBuilder = new StringBuilder("update ");
		StringBuilder fieldValue = new StringBuilder();
		List<Object> args = new ArrayList<>();
		sqlBuilder.append(tableName);
		sqlBuilder.append(" set ");
		map.forEach((field, value) -> {
			fieldValue.append(field);
			fieldValue.append(" = ?, ");
			args.add(value);
		});
		sqlBuilder.append(Util.removeSeparator(fieldValue));
		sqlBuilder.append(" ");
		sqlBuilder.append(where.getSql());
		if (where.getArgs() != null && where.getArgs().size() > 0) {
			args.addAll(where.getArgs());
		}
		return new PrepSqlResultImpl(sqlBuilder.toString(), args);
	}

    /**
     * 构建更新SQL语句
     * @param tableName 数据库表名
     * @param t 实体类对象
     * @param where 更新条件对象
     * @param <T> 实体类泛型
     * @return 构建后的SQL对象
     */
	public <T> PrepSqlResultImpl updateSqlByEntity(String tableName, T t, Where where){
		this.verifyWhere(where);
		StringBuilder sqlBuilder = new StringBuilder("update ");
		StringBuilder fieldValue = new StringBuilder();
		List<Object> args = new ArrayList<>();
		sqlBuilder.append(tableName);
		sqlBuilder.append(" set ");
		BeanInfo beanInfo = null;
		try {
			beanInfo = Introspector.getBeanInfo(t.getClass(), Object.class);
			PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
			for (PropertyDescriptor proper : propertyDescriptors) {
				String name = proper.getName();
				Method readMethod = proper.getReadMethod();
				Object invoke = readMethod.invoke(t);
				if(invoke == null){
					continue;
				}
				fieldValue.append(name);
				fieldValue.append(" = ?, ");
				args.add(invoke);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		sqlBuilder.append(Util.removeSeparator(fieldValue));
		sqlBuilder.append(" ");
		sqlBuilder.append(where.getSql());
		if (where.getArgs() != null && where.getArgs().size() > 0) {
			args.addAll(where.getArgs());
		}
		return new PrepSqlResultImpl(sqlBuilder.toString(), args);
	}


	/**
	 * @param tableName 表名
	 * @param mapListConfig 表名所对应的键值对数组
	 * @param whereList 条件数组
	 * @return 批量更新只适用于更新条件一样，但是参数不同的时候，比如更新条件都是id= ?,但是各id的数值不一样
	 */
	@Override
	public BatchSqlResultImpl updateBatchSql(String tableName, List<LinkedHashMap<String, Object>> mapListConfig, List<Where> whereList) {
		List<UtilLinkedHashMap<String, Object>> mapList = this.verifyMapList(mapListConfig);
		this.verifyWhereList(whereList);
		if (mapList.size() != whereList.size()) {
			throw new RuntimeException("mapList与whereList长度不一致！mapList size and whereList size Not the same!");
		}
		StringBuilder sqlBuilder = new StringBuilder("update ");
		StringBuilder fieldValue = new StringBuilder();
		sqlBuilder.append(tableName);
		sqlBuilder.append(" set ");
		List<List> args = new ArrayList<>();
		AtomicInteger i = new AtomicInteger();
		mapList.forEach(item -> {
			List<Object> arg = new ArrayList<>();
			item.forEach((field, value) -> {
				if (i.get() == 0) {
					fieldValue.append(field);
					fieldValue.append(" = ?, ");
				}
				arg.add(value);
			});
			if (whereList.get(i.get()).getArgs() != null && whereList.get(i.get()).getArgs().size() > 0) {
				arg.addAll(whereList.get(i.get()).getArgs());
			}
			args.add(arg);
			i.getAndIncrement();
		});
		sqlBuilder.append(Util.removeSeparator(fieldValue));
		sqlBuilder.append(" ");
		sqlBuilder.append(whereList.get(0).getSql());
		return new BatchSqlResultImpl(sqlBuilder.toString(), args);
	}

    /**
     * 通过实体类构建批量更新SQL
     * @param tableName 数据库表名
     * @param list 实体类集合
     * @param whereList 更新条件集合，一一对应更新数据集合
     * @param <T> 泛型
     * @return 构建后的批量SQL对象
     */
	public <T> BatchSqlResultImpl updateBatchSqlByEntity(String tableName, List<T> list, List<Where> whereList) {
		this.verifyWhereList(whereList);
		if (list.size() != whereList.size()) {
			throw new RuntimeException("List与whereList长度不一致！mapList size and whereList size Not the same!");
		}
		StringBuilder sqlBuilder = new StringBuilder("update ");
		StringBuilder fieldValue = new StringBuilder();
		sqlBuilder.append(tableName);
		sqlBuilder.append(" set ");
		List<List> args = new ArrayList<>();
		AtomicInteger i = new AtomicInteger();
		list.forEach(item -> {
			List<Object> arg = new ArrayList<>();
			BeanInfo beanInfo = null;
			try {
				beanInfo = Introspector.getBeanInfo(item.getClass(), Object.class);
				PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
				for (PropertyDescriptor proper : propertyDescriptors) {
					String name = proper.getName();
					Method readMethod = proper.getReadMethod();
					Object invoke = readMethod.invoke(item);
					if(invoke == null){
						continue;
					}
					if (i.get() == 0) {
						fieldValue.append(name);
						fieldValue.append(" = ?, ");
					}
					arg.add(invoke);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			if (whereList.get(i.get()).getArgs() != null && whereList.get(i.get()).getArgs().size() > 0) {
				arg.addAll(whereList.get(i.get()).getArgs());
			}
			args.add(arg);
			i.getAndIncrement();
		});
		sqlBuilder.append(Util.removeSeparator(fieldValue));
		sqlBuilder.append(" ");
		sqlBuilder.append(whereList.get(0).getSql());
		return new BatchSqlResultImpl(sqlBuilder.toString(), args);
	}

	/**
	 * 构建插入SQL语句
	 * @param tableName 表名
	 * @param mapConfig 参数
	 * @return 拼接好的SQL
	 */
	@Override
	public String insertSqlForString(String tableName, Map<String, Object> mapConfig) {
		UtilHashMap<String, Object> map = this.verifyMap(mapConfig);
		StringBuilder sqlBuilder = new StringBuilder("insert into ");
		sqlBuilder.append(tableName);
		StringBuilder fieldBuilder = new StringBuilder();
		StringBuilder valueBuilder = new StringBuilder();
		map.forEach((field, value) -> {
			fieldBuilder.append(field);
			fieldBuilder.append(", ");
			valueBuilder.append("'");
			valueBuilder.append(value);
			valueBuilder.append("'");
			valueBuilder.append(", ");
		});
		sqlBuilder.append(" ( ");
		sqlBuilder.append(Util.removeSeparator(fieldBuilder));
		sqlBuilder.append(" ) values ( ");
		sqlBuilder.append(Util.removeSeparator(valueBuilder));
		sqlBuilder.append(" )");
		return sqlBuilder.toString();
	}

	/**
	 * 构建更新SQL语句
	 * @param tableName 表名
	 * @param mapConfig 参数
	 * @return 拼接好的SQL
	 */
	@Override
	public String updateSqlForString(String tableName, Map<String, Object> mapConfig, WhereImpl where) {
		UtilHashMap<String, Object> map = this.verifyMap(mapConfig);
		this.verifyWhere(where);
		StringBuilder sqlBuilder = new StringBuilder("update ");
		StringBuilder fieldValue = new StringBuilder();
		sqlBuilder.append(tableName);
		sqlBuilder.append(" set ");
		map.forEach((field, value) -> {
			fieldValue.append(field);
			fieldValue.append(" = ");
			fieldValue.append("'");
			fieldValue.append(value);
			fieldValue.append("'");
			fieldValue.append(", ");
		});
		sqlBuilder.append(Util.removeSeparator(fieldValue));
		sqlBuilder.append(" ");
		sqlBuilder.append(where.getSql());
		return sqlBuilder.toString();
	}




	/**
	 * 验证构建SQL参数的，并且过滤到为null的数据
	 * @param map 验证SQL参数map对象
	 * @return 验证后的UtilHashMap
	 */
	public UtilHashMap<String, Object> verifyMap(Map<String, Object> map) {
		UtilHashMap<String, Object> filterMap = Util.createUtilHashMap()
				.uPutAll(map)
				.filter((key, value) -> !Objects.isNull(key) && !Objects.isNull(value));
		if (Util.mapIsNullOrEmpty(filterMap)) {
			throw new RuntimeException("map为空或没有数据！ map is null or empty!");
		}
		return filterMap;
	}

	/**
	 * 验证批量SQL构建的数据
	 * @param mapList 批量构建SQL的的工具
	 * @return 验证和过滤后的数据
	 */
	public List<UtilLinkedHashMap<String, Object>> verifyMapList(List<LinkedHashMap<String, Object>> mapList) {
		if (Objects.isNull(mapList)) {
			throw new RuntimeException("mapList为null！mapList is null!");
		}
		List<UtilLinkedHashMap<String, Object>> collect = mapList.stream().map(item ->
				Util.createUtilLinkedHashMap()
						.uPutAll(item)
						.filter((key, value) -> !Objects.isNull(key) && !Objects.isNull(value))
		).collect(Collectors.toList());
		if (mapList.size() == 0) {
			throw new RuntimeException("mapList没有数据！mapList is empty!");
		}
		return collect;
	}

	/**
	 * 验证where条件是否符合
	 * @param where where 条件对象
	 */
	private void verifyWhere(Where where) {
		if (where == null) {
			throw new RuntimeException("where为null！ where is null!");
		}
	}
	/**
	 * 验证where条件集合是否符合
	 * @param whereList where 条件对象集合
	 */
	private void verifyWhereList(List<Where> whereList) {
		if (whereList == null) {
			throw new RuntimeException("whereList为null！ whereList is null!");
		}
		whereList.forEach(item->{
			if(item == null){
				throw new RuntimeException("whereList中数据为null！ whereDate is null in whereList!");
			}
		});
	}
}
